package top.jacktgq.itheima.netty.protocol_design.groupchat.protocol;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageCodec;
import lombok.extern.slf4j.Slf4j;
import top.jacktgq.itheima.netty.protocol_design.groupchat.message.Message;
import top.jacktgq.itheima.netty.protocol_design.groupchat.protocol.serializer.Config;
import top.jacktgq.itheima.netty.protocol_design.groupchat.protocol.serializer.Serializer;

import java.util.List;

/**
 * @Author CandyWall
 * @Date 2021/3/24--13:52
 * @Description
 */
@Slf4j
@ChannelHandler.Sharable
/**
 * 必须和 LengthFieldBasedFrameDecoder 一起使用，确保接收到的 ByteBuf 消息是完整的
 */
public class MessageCodecSharable extends MessageToMessageCodec<ByteBuf, Message> {
    @Override
    protected void encode(ChannelHandlerContext ctx, Message msg, List<Object> out) throws Exception {
        ByteBuf outByteBuf = ctx.alloc().buffer();
        // 1. 魔数：4字节
        outByteBuf.writeBytes(new byte[]{'8', '8', '4', '8'});
        // 2. 版本号：1字节
        outByteBuf.writeByte(1);
        // 3. 序列化方式：1字节，0：jdk，1：json，2：protobuf，3：hessian
        // 从配置文件中读取序列化方式
        Serializer.Algorithm serializerAlgorithm = Config.getSerializerAlgorithm();
        outByteBuf.writeByte(serializerAlgorithm.ordinal());
        // 4. 消息类型：1字节
        outByteBuf.writeByte(msg.getMessageType());
        // 5. 请求序号：4字节
        outByteBuf.writeInt(msg.getSequenceId());

        // 6. 填充：1字节（无实际意义）
        outByteBuf.writeByte(0xff);

        // 获取内容的字节数组
        byte[] bytes = serializerAlgorithm.serialize(msg);
        // 7. 正文长度：4字节
        outByteBuf.writeInt(bytes.length);
        // 8. 消息内容：bytes.length字节
        outByteBuf.writeBytes(bytes);
        // 一次消息传输总共字节数
        // 魔数 + 版本号 + 序列化方式 + 消息类型 + 请求序号 + 填充位 + 正文长度 + 消息内容
        // 4    + 1     + 1         + 1        + 4       + 1      + 4       +  bytes.length
        // 共计 16 + bytes.length 字节
        out.add(outByteBuf);
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf inByteBuf, List<Object> out) throws Exception {
        // 1. 魔数：4字节
        int magicNum = inByteBuf.readInt();
        // 2. 版本号：1字节
        byte version = inByteBuf.readByte();
        // 3. 序列化方式：1字节，0：jdk，1：json，2：protobuf，3：hessian
        byte serializerType = inByteBuf.readByte();
        // 4. 消息类型：1字节
        byte msg_type = inByteBuf.readByte();
        // 5. 请求序号：4字节
        int sequenceId = inByteBuf.readInt();
        // 6. 先读取一个字节的填充位
        inByteBuf.readByte();
        // 7. 正文长度：4字节
        int msg_length = inByteBuf.readInt();
        // 8. 消息内容：bytes.length字节
        byte[] bytes = new byte[msg_length];
        inByteBuf.readBytes(bytes);

        // 找到反序列化时的算法
        Serializer.Algorithm serializer = Serializer.Algorithm.values()[serializerType];
        // 必须确定具体子消息类型，不能转成父类，因为父类是个抽象类
        Object message = serializer.deserialize(Message.getMessageClass(msg_type), bytes);

        log.debug("魔数：{}，版本号：{}，序列化方式：{}，消息类型：{}，请求序号：{}，正文长度：{}", magicNum, version, serializerType, msg_type, sequenceId, msg_length, msg_length);
        log.debug("消息内容：{}", message);
        out.add(message);
    }
}
